package CacheLayer;

import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import DomainLayer.AbstractEntity;
import Helpers.ApplicationLogger;

public class TimeFrameCache extends AbstractCache{

	private static final long serialVersionUID = 1L;

	public TimeFrameCache(){}

	private class TimeBasedFrame extends BaseFrame{	
		private Integer timeSpan = 5;

		private Calendar elapsedDateTime = Calendar.getInstance();
		public Calendar getElapsedDateTime(){
			return elapsedDateTime;
		}
		public Boolean isElapsed(){
			return Calendar.getInstance().after(getElapsedDateTime());
		}
		
		protected Boolean toRemove=false;
		
		public void refreshTimeOut(){
			elapsedDateTime.add(Calendar.MINUTE, timeSpan);
		}
		
		public TimeBasedFrame(AbstractEntity entity, Integer timeSpanMin){
			super(entity);
			if(timeSpanMin != null){
				timeSpan = timeSpanMin;
			}
			refreshTimeOut();
		}
	}
	
	private class Timer implements Runnable	{
		Thread runner;
		private TimeFrameCache cache;
		
		public Timer(TimeFrameCache iCache){
			cache = iCache;
			runner = new Thread(this);
			runner.start();
		}
		
		public void run() {
			ApplicationLogger.getInstance().LOG.debug("Timer runned");
			Set<Map.Entry<Integer, TimeFrameCache.TimeBasedFrame>> set = cache.entrySet();
			
			Boolean cacheIsClear = false;
			for (Map.Entry<Integer, TimeBasedFrame> currentFrame : set) {
				ApplicationLogger.getInstance().LOG.debug("elapsed:" + currentFrame.getValue().elapsedDateTime);
				ApplicationLogger.getInstance().LOG.debug("current:" + Calendar.getInstance());
				if(currentFrame.getValue().isElapsed()){
					currentFrame.getValue().toRemove = true;
					cacheIsClear=true;
				}else{
					cacheIsClear=false;
				}
			}
			
			for(Iterator<TimeFrameCache.TimeBasedFrame> iter = cache.values().iterator(); iter.hasNext();){
				TimeBasedFrame currentFrame = iter.next();
				if(currentFrame.toRemove){
					iter.remove();
				}
			}
			
			if(cacheIsClear){
				ApplicationLogger.getInstance().LOG.debug("Cache is clear");
				return;
			}else{
				try {
					ApplicationLogger.getInstance().LOG.debug("Sleep");
					Thread.sleep(1000);
					run();
				} catch (InterruptedException e) {
					ApplicationLogger.getInstance().LOG.error(e.getMessage());
				}
			}
		}
	}
	
	public void addEntityToCache(AbstractEntity entity) {
		if(get(entity.getId()) == null){
			put(entity.getId(), new TimeBasedFrame(entity, null));
			startTimer();
		}
	}
	public void addEntityToCache(AbstractEntity entity, Integer timeSpanMin) {
		if(get(entity.getId()) == null){
			put(entity.getId(), new TimeBasedFrame(entity, timeSpanMin));
			startTimer();
		}
	}
	public AbstractEntity getEntityFromCache(Integer id){		
		if(!containsKey(id)){
			return null;
		}
		((TimeBasedFrame)get(id)).refreshTimeOut();
		startTimer();
		return ((TimeBasedFrame)get(id)).getEntity();
	}
	
	private void startTimer(){
		Timer tr = new Timer(this);
	}
}
